package com.zhj.annotation.processor;


import java.util.Map;
import java.util.Objects;
import java.util.Set;

import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.Filer;
import javax.annotation.processing.Messager;
import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.RoundEnvironment;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.AnnotationValue;
import javax.lang.model.element.Element;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.util.Types;
import javax.tools.Diagnostic;

import lombok.Data;

@Data
public abstract class AbstractAnnotationProcessor extends AbstractProcessor {

    protected Messager messager;

    protected Types typeUtils;

    protected Filer filer;

    @Override
    public synchronized void init(ProcessingEnvironment processingEnv) {
        this.messager = processingEnv.getMessager();
        this.typeUtils = processingEnv.getTypeUtils();
        this.filer = processingEnv.getFiler();
    }

    /**
     * 设置支持的版本
     * @return
     */
    @Override
    public SourceVersion getSupportedSourceVersion() {
        return SourceVersion.latestSupported();
    }

    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
        try {
            return processImpl(annotations, roundEnv);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

    /**
     * 获取对应注解的属性值
     * @param annotationMirror
     * @param elementName
     * @return
     */
    protected AnnotationValue getAnnotationValue(AnnotationMirror annotationMirror,
                                                 String elementName) {
        Objects.requireNonNull(annotationMirror);
        Objects.requireNonNull(elementName);
        for (Map.Entry<? extends ExecutableElement, ? extends AnnotationValue> entry :
            this.processingEnv.getElementUtils().getElementValuesWithDefaults(annotationMirror).entrySet()) {
            if (entry.getKey().getSimpleName().contentEquals(elementName)) {
                return entry.getValue();
            }
        }
        String annotationName = annotationMirror.getAnnotationType().toString();
        throw new IllegalArgumentException(String.format("@%s does not define an element %s()", annotationName, elementName));
    }

    protected abstract boolean processImpl(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv);


    protected void logInfo(String msg) {
        this.messager.printMessage(Diagnostic.Kind.NOTE, msg);
    }

    protected void errorInfo(String msg) {
        this.messager.printMessage(Diagnostic.Kind.ERROR, msg);
    }
}
